#include "AiSpeler.h"

#include "Map.h"
#include "Spel.h"
#include "Robot.h"

void AiSpeler::programmeerRobot(Robot* robot)
{
	// alle mogelijke combinaties testen ( 9! / 4! = 15120 mogelijkheden - maximaal)
	// recursie
	m_bestSoFar = -1;
	vector<Kaart*> chosen;
	m_robot = robot;
	m_best.clear();
	findOptimalSolution(chosen, m_kaarten);
}

void AiSpeler::findOptimalSolution(vector<Kaart*> chosen, vector<Kaart*> toChooseFrom)
{
	if( toChooseFrom.empty() || chosen.size() == 5 )	// stopconditie
	{
		// kijken hoe het robotje loopt en er een score aan geven.
		Robot dummy("Dummy");
		Positie pos= m_robot->getPositie();
		dummy.setPositie( pos.x, pos.y);
		dummy.setRotatie( m_robot->getRotatie() );
		dummy.setSchade( m_robot->getSchade() );
		for(size_t i = 0; i < chosen.size(); i++)
		{
			chosen[i]->project( &dummy, m_spel ); 
			if( dummy.getSchade() == 9 )
				return; // kan niet de beste oplossing zijn
		}
		Positie eindpos = dummy.getPositie();

		int result = m_hoogteMap[m_robot->getNextCheckpoint()][eindpos.x][eindpos.y];
		if( result < m_bestSoFar || m_bestSoFar == -1)
		{
			m_bestSoFar = result;
			m_best = chosen;
		}
	}
	else
	{
		for(size_t i = 0; i < toChooseFrom.size(); i++)
		{
			vector<Kaart*> tempChosen = chosen;
			vector<Kaart*> tempToChooseFrom;
			// enige manier om 1 element eruit te halen??
			for(size_t j = 0; j < toChooseFrom.size(); j++)
				if( j != i )
					tempToChooseFrom.push_back( toChooseFrom[j] );
		
			tempChosen.push_back( toChooseFrom[i] );
			findOptimalSolution( tempChosen, tempToChooseFrom);		// recursie
		}		
	}
}

void AiSpeler::updateBord( const Spel* spel )
{
	if( !m_spel )
		computeStrategy( spel );
}

// deze maakt een 'hoogte map' van alle checkpoint.. dus het enige wat hij dan moet doen is van de berg afhuppelen
// distance is manhattan distance
void AiSpeler::computeStrategy( const Spel* spel )
{
	const Map& map = spel->getMap();
	
	// beginnen met opvullen mappen
	m_hoogteMap.resize(3);
	for(int cpNr = 0; cpNr < 3; cpNr++)
	{
		m_hoogteMap[cpNr].resize(map.width());
		for(size_t x = 0; x < map.width(); x++)
		{
			m_hoogteMap[cpNr][x].resize(map.height());
			for(size_t y = 0; y < map.height(); y++)
				m_hoogteMap[cpNr][x][y] = -1;		// -1 betekent: nog niet bezocht, -2 -> onmogelijk
		}
	}

	// initializatie
	for(size_t x = 0; x < map.width(); x++)
		for(size_t y = 0; y < map.height(); y++)
		{
			const Vakje* vakje = map.getVakje(x, y);
			char type = vakje->serialize()[0];
			if( type == 'C' )
			{
				int nr = vakje->serialize()[1] - '0';
				m_hoogteMap[nr][x][y] = 0;	// hier moeten we zijn: -> laagste punt
			}
			else if( vakje->isObstakel() || type == 'A' )
			{
				for(int i = 0; i < 3; i++) 
					m_hoogteMap[i][x][y] = -2;	// hier kunnen we niet zijn
			}
		}

	// opvullen
	for(int cpNr = 0; cpNr < 3; cpNr++)
	{
		bool morePossibilities = true;
		int lowest = 0;
		while( morePossibilities )
		{
			morePossibilities = false;
			for(size_t x = 0; x < map.width(); x++)
				for(size_t y = 0; y < map.height(); y++)
				{
					if( m_hoogteMap[cpNr][x][y] == lowest ) 
					{
						// boven en onder toevoegen
						if( y < map.height() - 1 && m_hoogteMap[cpNr][x][y + 1] == -1)
						{
							m_hoogteMap[cpNr][x][y + 1] = lowest + 1;
							morePossibilities = true;
						}
						if( y > 0 && m_hoogteMap[cpNr][x][y - 1] == -1)
						{
							m_hoogteMap[cpNr][x][y - 1] = lowest + 1;
							morePossibilities = true;
						}
						// links en rechts
						if( x < map.width() - 1 && m_hoogteMap[cpNr][x + 1][y] == -1){
							m_hoogteMap[cpNr][x + 1][y] = lowest + 1;
							morePossibilities = true;
						}
						if( x > 0 && m_hoogteMap[cpNr][x][y - 1] == -1){
							m_hoogteMap[cpNr][x - 1][y] = lowest + 1;
							morePossibilities = true;
						}
					}
				}

			lowest++;
		}
	}
	// moeten we bijhouden voor dadelijk mogelijke wegen uit te testen
	m_spel = spel;
}

